﻿/**

 * Copyright (c) 2015-2016, FastDev 刘强 (fastdev@163.com).

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


using OF.DistributeService.Core.Entity;
using OF.DistributeService.Core.Entity.Service;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace OF.DistributeService.Core.Attribute
{
    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
    public class OFDistributeServiceAttribute : System.Attribute
    {        
        private static Type serviceAttrType = typeof(OFDistributeServiceAttribute);

        /// <summary>
        /// 服务名，同一应用中必须唯一
        /// </summary>
        public string ServiceName { get; set; }

        /// <summary>
        /// 版本
        /// </summary>
        public string Version { get; set; }

        /// <summary>
        /// 此Service的虚拟路径，默认设置为 Webapi 的 Controller 名即可
        /// </summary>
        public string VirtualPath { get; set; }

        /// <summary>
        /// 默认的Http Method
        /// </summary>
        public ApiHttpMethod DefaultMethod { get; set; }

        /// <summary>
        /// 默认 Http Post内容格式 (Json/MSGPack)
        /// </summary>
        public ApiContentFormat DefaultContentFormat { get; set; }

        public OFDistributeServiceAttribute()
        {
            DefaultMethod = ApiHttpMethod.Get;
            DefaultContentFormat = ApiContentFormat.JSON;
        }
        
        public static string GetServiceName(OFDistributeServiceAttribute serviceAttr, Type interfaceType)
        {
            string serviceName;
            if (string.IsNullOrWhiteSpace(serviceAttr.ServiceName))
            {
                serviceName =  interfaceType.FullName;
            }
            else
            {
                serviceName = serviceAttr.ServiceName;
            }
            return serviceName;
        }

        public static Func<Type, bool> GetFilterByNSPrefix(string ns)
        {
            return (type) =>
            {
                return type.FullName.IndexOf(ns + ".") == 0;
            };
        }

        public static List<ClientToAppServiceConfig> GetClientToAppConfigList(Assembly assembly, Func<Type, bool> filter = null)
        {
            var serviceTypeList = assembly.GetTypes()
                .Where(type => type.GetCustomAttribute(serviceAttrType, true) != null);
            if (filter != null)
            {
                serviceTypeList = serviceTypeList.Where(filter);
            }
            List<Type> typeList = serviceTypeList.ToList();
            List<ClientToAppServiceConfig> result = new List<ClientToAppServiceConfig>(typeList.Count);
            foreach (Type type in typeList)
            {
                result.Add(GetClientToAppConfig(type));
            }
            return result;
        }

        public static ClientToAppServiceConfig GetClientToAppConfig(Type interfaceType)
        {
            ApiServiceAttrMeta apiServiceAttrMeta = GetApiServiceAttrMeta(interfaceType);
            if (apiServiceAttrMeta == null)
            {
                return null;
            }
            return new ClientToAppServiceConfig {
                InterfaceType = apiServiceAttrMeta.InterfaceType,
                ServiceName = GetServiceName(apiServiceAttrMeta.ServiceAttribute, apiServiceAttrMeta.InterfaceType),
                Version = apiServiceAttrMeta.ServiceAttribute.Version
            };
        }

        public static ApiServiceAttrMeta GetApiServiceAttrMeta(Type type)
        {
            OFDistributeServiceAttribute attr = type.GetCustomAttribute(serviceAttrType, true) as OFDistributeServiceAttribute;
            if (attr != null)
            {
                return new ApiServiceAttrMeta
                {
                    ControllerType = type,
                    InterfaceType = type,
                    ServiceAttribute = attr
                };
            }
            else
            {
                var interfaces = type.GetInterfaces();
                if (interfaces != null)
                {
                    foreach (var inter in interfaces)
                    {
                        attr = inter.GetCustomAttribute(serviceAttrType, true) as OFDistributeServiceAttribute;
                        if (attr != null)
                        {
                            return new ApiServiceAttrMeta
                            {
                                ControllerType = type,
                                InterfaceType = inter,
                                ServiceAttribute = attr
                            };
                        }
                    }
                }
                return null;
            }
        }
    }
}
